package toolz;

import input.HEATMAP_BUFFER_IO;

import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;

import model.IMSFile;
import model.detection.wst.WSTpeakfinder;
import model.filter.GaussFilter;
import model.filter.MatrixFilter;
import model.filter.MeanFilter;
import DATA.iDataSetParts.Peak;
import DATA.iDataSetParts.Peaklist;

public class ImageMethods {

	public static boolean done = false;
	public static double[] compensationSpectra;
	public static double[][] lastMap = null;

	public static int getRipPos(double[][] map) {
		System.out.print("Searching for RIP position ..");
		double[] maxima = new double[map[0].length];
		int[] ripXcoord = new int[map[0].length];

		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[x].length; y++) {
				if (map[x][y] > maxima[y]) {
					maxima[y] = map[x][y];
					ripXcoord[y] = x;
				}
			}
		}
		Arrays.sort(ripXcoord);
		int ripPos = ripXcoord[(int) (ripXcoord.length * 0.5)];

		System.out.println(".. found at " + ripPos);
		return (ripPos);
	}

	private static double[][] substractSimilaritie(double[][] map) {
		System.out.print("Copmpensating RIPtailing ..");
		double medianPercentage = 0.3; // 0.3
		double[] similaritieSpectrum = new double[map.length];

		int stoppRT = map[0].length;
		int startRT = 0;

		double[] Ycolumn = new double[stoppRT - startRT];
		int quantilePosition = (int) (Ycolumn.length * medianPercentage);
		System.out.println("quantilepostion: " + quantilePosition);

		// compute similaritie
		for (int x = 0; x < map.length; x++) {
			for (int y = startRT; y < stoppRT; y++) {
				Ycolumn[y - startRT] = map[x][y];
			}
			Arrays.sort(Ycolumn);
			similaritieSpectrum[x] = Ycolumn[quantilePosition];
			// System.out.println(similaritieSpectrum[x]);
		}

		compensationSpectra = similaritieSpectrum;

		// substract similaritie from all spectra
		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[0].length; y++) {
				map[x][y] = Math.max(0, map[x][y] - similaritieSpectrum[x]);
			}
		}
		System.out.println(".. done");
		return map;
	}

	// efficient median
	// public static double[][] filterMedian(double[][] map) {
	// System.out.print("Using Median Filter (5x5) ..");
	//
	// int xDim = map.length,
	// yDim = map[0].length,
	// maskSize = 5,
	// maskR = (maskSize - 1) / 2,
	// medianPos = ((maskSize * maskSize + 1) / 2) - 1;
	// double[][] newArray = new double[xDim][yDim];
	// double[] elements = new double[maskSize * maskSize];
	// double[][] mask = new double[3][5 * 5];
	//
	//
	// for (int x = 0; x < newArray.length; x++) {
	// boolean lineStart = true;
	// for (int y = 0; y < newArray[x].length; y++) {
	// int ec = 0;
	// if (lineStart) {
	// for (int mx = maskR * -1; mx <= maskR; mx++) {
	// for (int my = maskR * -1; my <= maskR; my++) {
	//
	// lineStart = false;
	// try {
	// mask[1][ec] = x + mx;
	// mask[2][ec] = y + my;
	// mask[3][ec] = map[x + mx][y + my];
	// ec++;
	//
	// } catch (IndexOutOfBoundsException e) {
	// mask[1][ec] = x + mx;
	// mask[2][ec] = y + my;
	// mask[3][ec] = 0;
	// ec++;
	// }
	// }
	// }
	// } else {
	// int shift = 1;
	// for (int mx = maskR * -1; mx <= maskR; mx++) {
	// for (int my = maskR * -1+shift; my <= maskR-shift; my++) {
	// for (int i = 0; i < ec; i++) {
	// mask[1][i] = x + mx;
	// mask[2][i] = y + my;
	// mask[3][i] = map[x + mx][y + my];
	// }
	// }
	// }
	// }
	//
	// Arrays.sort(mask);
	// newArray[x][y] = elements[medianPos]; //median
	// }
	// }
	// System.out.println(".. done");
	// return (newArray);
	// }
	public static double[][] localBaselineCorrection(final double[][] map, int maskSize) {
		System.out.print("Using Local Baseline Correction ..");
		final int xDim = map.length, yDim = map[0].length, maskR = (maskSize - 1) / 2, medianPos = ((maskSize
				* maskSize + 1) / 2) - 1, eC = 0;
		final double[][] newArray = new double[xDim][yDim];
		final double[] elements = new double[maskSize * maskSize];

		// Runnable runnable = new Runnable() {
		//
		// public void run() {
		// WaitJDialog wait = new WaitJDialog("Local baseline correction ...", newArray.length);
		// boolean abort = false;
		// for start

		int ec = eC;

		for (int x = 0; x < newArray.length; x++) {
			for (int y = 0; y < newArray[0].length; y++) {
				ec = 0;
				for (int mx = maskR * -1; mx <= maskR; mx++) {
					for (int my = maskR * -1; my <= maskR; my++) {
						try {
							elements[ec] = map[x + mx][y + my];
						} catch (IndexOutOfBoundsException e) {
							elements[ec] = 0;
						}
						ec++;
					}
				}
				Arrays.sort(elements);
				newArray[x][y] = Math.max(map[x][y] - elements[medianPos], 0); // median
			}

			// abort = wait.tick(x, "");
			// if (abort) {
			// break;
			// }
		}

		// wait.dispose();

		// for end
		// };
		//
		// Thread thread = new Thread(runnable);
		//
		// thread.start();

		System.out.println(".. done");
		return (newArray);

	}

	public static double[][] filterMedian(double[][] map, int maskSize) {
		System.out.print("Median filter (masksize:" + maskSize + ") ..");
		int xDim = map.length, yDim = map[0].length, maskR = (maskSize - 1) / 2, medianPos = ((maskSize * maskSize + 1) / 2) - 1, eC;
		double[][] newArray = new double[xDim][yDim];
		double[] elements = new double[maskSize * maskSize];

		for (int x = 0; x < newArray.length; x++) {
			for (int y = 0; y < newArray[0].length; y++) {
				eC = 0;
				for (int mx = maskR * -1; mx <= maskR; mx++) {
					for (int my = maskR * -1; my <= maskR; my++) {
						try {
							elements[eC] = map[x + mx][y + my];
						} catch (IndexOutOfBoundsException e) {
							elements[eC] = 0;
						}
						eC++;
					}
				}
				Arrays.sort(elements);
				newArray[x][y] = elements[medianPos]; // median
				// overwrite spectra 1-3
				if (y <= 3) {
					newArray[x][y] = map[x][y];
				}

			}
		}
		System.out.println(".. done");
		return (newArray);
	}

	public static double[][] filterMedian(double[][] map) {
		System.out.print("Using Median Filter (5x5) ..");

		int xDim = map.length, yDim = map[0].length, maskSize = 5, maskR = (maskSize - 1) / 2, medianPos = ((maskSize
				* maskSize + 1) / 2) - 1, eC;
		double[][] newArray = new double[xDim][yDim];
		double[] elements = new double[maskSize * maskSize];

		for (int x = 0; x < newArray.length; x++) {
			for (int y = 0; y < newArray[0].length; y++) {
				eC = 0;
				for (int mx = maskR * -1; mx <= maskR; mx++) {
					for (int my = maskR * -1; my <= maskR; my++) {
						// faster ?
						// if ( (x+mx >= 0) &&
						// (y+my >= 0) &&
						// (x+mx < xDim) &&
						// (y+my < yDim)){
						try {
							elements[eC] = map[x + mx][y + my];
						} catch (IndexOutOfBoundsException e) {
							elements[eC] = 0;
						}
						// }
						// else elements[eC] = 0;

						eC++;
					}

				}
				Arrays.sort(elements);
				newArray[x][y] = elements[medianPos]; // median
			}

		}
		System.out.println(".. done");
		return (newArray);
	}

//	public static double[][] fastMedian(double[][] map) {
//
//		System.out.print("Using Fast Median Filter (5x5) ..");
//		boolean doOutput = true;
//
//		int xDim = map.length;
//		int yDim = map[0].length;
//		int maskSize = 5;
//	//	int maskR = (maskSize - 1) / 2;
//		int medianPos = ((maskSize	* maskSize + 1) / 2) - 1;
//	//	int eC;
//		
//		double[][] newArray = new double[xDim][yDim];
//
//		ArrayList<Double> elementlist = new ArrayList<Double>();
//
//		for (int y = 0; y < newArray[0].length; y++) {
//			boolean newline = true;
//			// double[][] maskbuffer = new double[5][5];
//			HashMap<Integer, Double> maskhash = new HashMap<Integer, Double>(25);
//
//			for (int x = 0; x < newArray.length; x++) {
//				if (newline == true) {
//					elementlist.clear();
//					double value = 0.0;
//					for (int mx = -2; mx <= 2; mx++) {
//						for (int my = -2; my <= 2; my++) {
//							value = 0.0;
//							try {
//								value = map[x + mx][y + my];
//								// maskbuffer[mx+2][my+2] = map[x + mx][y + my];
//								// maskhash.put((x+1+mx+2)*10000+(1+my+2),map[x + mx][y + my]);
//								medianPut(value, elementlist);
//							} catch (IndexOutOfBoundsException e) {
//								value = 0.0;
//								elementlist.add(0, 0.0);
//								// maskbuffer[mx+2][my+2] = 0.0;
//							} finally {
//
//								maskhash.put((x + 1 + mx + 2) * 10 + (my + 2), value);
//								if (doOutput) {
//									System.out.println("init adding " + (x + 1 + mx + 2) * 10 + (my + 2));
//								}
//							}
//
//						}
//					}
//
//					newline = false;
//				} else {
//
//					for (int i = 0; i < 5; i++) {
//						elementlist.remove(((1 + x) * 10) + (i));
//						maskhash.remove(((1 + x) * 10) + (i));
//						if (doOutput) {
//							System.out.println("removing " + ((1 + x) * 10) + (i));
//						}
//					}
//					// elementlist.remove(maskbuffer[0][0]);
//					// elementlist.remove(maskbuffer[0][1]);
//					// elementlist.remove(maskbuffer[0][2]);
//					// elementlist.remove(maskbuffer[0][3]);
//					// elementlist.remove(maskbuffer[0][4]);
//
//					// for (int i = 0; i <= 3; i++) {
//					// maskbuffer[i][0] = maskbuffer[i+1][0];
//					// maskbuffer[i][1]= maskbuffer[i+1][1];
//					// maskbuffer[i][2]= maskbuffer[i+1][2];
//					// maskbuffer[i][3]= maskbuffer[i+1][3];
//					// maskbuffer[i][4]= maskbuffer[i+1][4];
//					// }
//					double value = 0;
//					int yshift = -4;
//					try {
//						value = map[x + 2][y - yshift];
//					} catch (ArrayIndexOutOfBoundsException ex) {
//						value = 0.0;
//					} finally {
//						medianPut(value, elementlist);
//						maskhash.put((1 + x + 2) * 10 + (y - yshift), value);
//						if (doOutput) {
//							System.out.println("adding " + (1 + x + 2) * 10 + (y - yshift));
//						}
//					}
//
//					yshift = -3;
//					try {
//						value = map[x + 2][y - yshift];
//					} catch (ArrayIndexOutOfBoundsException ex) {
//						value = 0.0;
//					} finally {
//						medianPut(value, elementlist);
//						maskhash.put((1 + x + 2) * 10 + (y - yshift), value);
//						if (doOutput) {
//							System.out.println("adding " + (1 + x + 2) * 10 + (y - yshift));
//						}
//					}
//
//					yshift = -2;
//					try {
//						value = map[x + 2][y - yshift];
//					} catch (ArrayIndexOutOfBoundsException ex) {
//						value = 0.0;
//					} finally {
//						medianPut(value, elementlist);
//						maskhash.put((1 + x + 2) * 10 + (y - yshift), value);
//						if (doOutput) {
//							System.out.println("adding " + (1 + x + 2) * 10 + (y - yshift));
//						}
//					}
//
//					yshift = -1;
//					try {
//						value = map[x + 2][y - yshift];
//					} catch (ArrayIndexOutOfBoundsException ex) {
//						value = 0.0;
//					} finally {
//						medianPut(value, elementlist);
//						maskhash.put((1 + x + 2) * 10 + (y - yshift), value);
//						if (doOutput) {
//							System.out.println("adding " + (1 + x + 2) * 10 + (y - yshift));
//						}
//					}
//
//					yshift = 0;
//					try {
//						value = map[x + 2][y - yshift];
//					} catch (ArrayIndexOutOfBoundsException ex) {
//						value = 0.0;
//					} finally {
//						medianPut(value, elementlist);
//						maskhash.put((1 + x + 2) * 10 + (y - yshift), value);
//						if (doOutput) {
//							System.out.println("adding " + (1 + x + 2) * 10 + (y - yshift));
//						}
//					}
//
//					// try {
//					// medianPut(map[x + 2][y -1], elementlist);
//					// maskbuffer[4][3] = map[x + 2][y -1];
//					//
//					// } catch (ArrayIndexOutOfBoundsException ex) {
//					// elementlist.add(0, 0.0);
//					// maskbuffer[4][3] = 0.0;
//					//
//					// }
//					// try {
//					// medianPut(map[x + 2][y + -0], elementlist);
//					// maskbuffer[4][2] = map[x + 2][y + -0];
//					//
//					// } catch (ArrayIndexOutOfBoundsException ex) {
//					// elementlist.add(0, 0.0);
//					// maskbuffer[4][2] =0.0;
//					//
//					// }
//					// try {
//					// medianPut(map[x + 2][y + 1], elementlist);
//					// maskbuffer[4][1] = map[x + 2][y + 1];
//					//
//					// } catch (ArrayIndexOutOfBoundsException ex) {
//					// elementlist.add(0, 0.0);
//					//
//					// maskbuffer[4][1] = 0.0;
//					// }
//					// try {
//					// medianPut(map[x + 2][y + 2], elementlist);
//					// maskbuffer[4][0] = map[x + 2][y + 2];
//					//
//					// } catch (ArrayIndexOutOfBoundsException ex) {
//					// elementlist.add(0, 0.0);
//					// maskbuffer[4][0] = 0.0;
//					//
//					// }
//				}
//				newArray[x][y] = elementlist.get(medianPos);
//			}
//
//		}
//		System.out.println(".. done");
//		return (newArray);
//	}
//
//	static private int medianPut(double d, ArrayList<Double> li) {
//		int pos = 0;
//		if (d >= li.get(li.size() - 1)) {
//			li.add(d);
//			pos = li.size();
//		} else if (d <= li.get(0)) {
//			li.add(0, d);
//		} else {
//			int idx = Collections.binarySearch(li, d);
//			if (idx >= 0) {
//				li.add(idx, d);
//				pos = idx;
//			} else {
//				idx = (-1) * (idx + 1);
//				li.add(idx, d);
//			}
//
//		}
//		// System.out.println("putting "+d+" at pos "+pos);
//		return pos;
//
//	}

	public static double[][] filterGauss(double[][] map) {
		System.out.print("Using Gaussian Filter ..");
		double newArray[][] = new double[map.length][map[0].length];
		double[][] mask = { { 1, 2, 1 }, { 2, 4, 2 }, { 1, 2, 1 } };
		int maskRadius = (mask.length - 1) / 2;
		int maskSum = 0;
		for (int i = 0; i < mask.length; i++) {
			for (int j = 0; j < mask[i].length; j++) {
				maskSum += mask[i][j];
			}
		}

		for (int x = maskRadius; x < newArray.length - maskRadius; x++) {
			for (int y = maskRadius; y < newArray[x].length - maskRadius; y++) {
				for (int i = -maskRadius; i <= maskRadius; i++) {
					for (int j = -maskRadius; j <= maskRadius; j++) {
						newArray[x][y] += (map[x + i][y + j] * mask[i + maskRadius][j + maskRadius]) / maskSum;
					}
				}
			}
		}
		System.out.println(".. done");
		return (newArray);
	}

	public static double[][] normArray(double[][] map) {
		System.out.print("Computing min/max intensities Vs/cm� ..");

		double min = 99999, max = -99999;
		double newArray[][] = new double[map.length][map[0].length];
		// get min/max values

		int borderSkip = 5;

		for (int i = 0 + borderSkip; i < map.length - borderSkip; i++) {
			for (int j = 0 + borderSkip; j < map[i].length - borderSkip; j++) {
				if (map[i][j] > max) {
					max = map[i][j];
				}

				if (map[i][j] < min) {
					min = map[i][j];
				}

			}
		}

		System.out.println(".. min = " + min + " max = " + max);

		System.out.print("Normalizing values between " + min + " and " + max + " to [0,1] ..");

		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				double fnorm = (map[i][j] - min) / (max - min);
				newArray[i][j] = fnorm;
			}

		}
		System.out.println(".. done");
		return (newArray);
	}

	public static double[][] normArray(double[][] map, double min, double max) {
		System.out.print("Spreading Values between " + min + " and " + max + " to 0 and 1 ..");
		double newArray[][] = new double[map.length][map[0].length];
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				if (map[i][j] >= min && map[i][j] <= max) {
					newArray[i][j] = (map[i][j] - min) / (max - min);
				}

				if (map[i][j] < min) {
					newArray[i][j] = 0;
				}

				if (map[i][j] > max) {
					newArray[i][j] = 1;
				}

			}
		}
		System.out.println(".. done");
		return (newArray);
	}

	public static double[][] invertArray(double[][] map) {
		double max = -999;
		// get min/max values
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				if (map[i][j] > max) {
					max = map[i][j];
				}

			}
		}

		System.out.println("Inverting (f'=" + max + "-f) ..");
		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[x].length; y++) {
				map[x][y] = (max - map[x][y]);
			}

		}
		System.out.println(".. done");
		return (map);

	}

	public static double[] determSpreadValues(double[][] map, int ripWidth) {
		double[] minmax = new double[2];
		int ripPos = getRipPos(map);
		int xStart = ripPos + ripWidth, xEnd = map.length - 2;
		int yStart = 9, yEnd = map[0].length - 2;

		double[] gigaArray = new double[(xEnd - xStart) * (yEnd - yStart)];

		int gigacount = 0;
		for (int x = xStart; x < xEnd - xStart; x++) {
			for (int y = yStart; y < yEnd - yStart; y++) {
				gigaArray[gigacount] = map[x][y];
				gigacount++;

			}

		}

		Arrays.sort(gigaArray);
		minmax[0] = gigaArray[(int) ((gigaArray.length - 1) * 0.00001)];
		minmax[1] = gigaArray[(int) ((gigaArray.length - 1) * 0.99999)];

		return minmax;
	}

	public static double[] getMinMaxQuantiles(double[][] map) {
		double[] minmax = new double[2];

		int xStart = 5, xEnd = map.length - 5;
		int yStart = 5, yEnd = map[0].length - 5;

		double[] gigaArray = new double[(xEnd - xStart) * (yEnd - yStart)];

		int gigacount = 0;
		for (int x = xStart; x < xEnd - xStart; x++) {
			for (int y = yStart; y < yEnd - yStart; y++) {
				gigaArray[gigacount] = map[x][y];
				gigacount++;

			}

		}

		Arrays.sort(gigaArray);
		minmax[0] = gigaArray[(int) ((gigaArray.length - 1) * 0.00001)];
		minmax[1] = gigaArray[(int) ((gigaArray.length - 1) * 0.99999)];

		return minmax;
	}

	private static double[][] baselineCorrection(double[][] map) {

		int rippos = getRipPos(map);

		int xstart = (int) (rippos * 0.1);
		int xstopp = (int) (rippos * 0.8);
		int ystart = 3;
		int ystopp = map[0].length - 6;
		int dim = (xstopp - xstart) * (ystopp - ystart);

		double[] blc = new double[dim];
		int i = 0;
		for (int x = xstart; x < xstopp; x++) {
			for (int y = ystart; y < ystopp; y++) {
				blc[i] = map[x][y];
				i++;

			}

		}
		Arrays.sort(blc);
		double blcMedian = blc[(int) (dim * 0.9)];

		System.out.println("Baseline = " + blcMedian);

		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[0].length; y++) {
				map[x][y] = map[x][y] - blcMedian;
			}

		}

		return map;
	}

	private static double[][] baselineCorrectionSpectraWise(double[][] map) {

		int rippos = getRipPos(map);

		int xstart = (int) (rippos * 0.1);
		int xstopp = (int) (rippos * 0.8);

		int dim = (xstopp - xstart);

		for (int y = 0; y < map[0].length; y++) {

			double[] blc = new double[dim];
			int i = 0;
			for (int x = xstart; x < xstopp; x++) {
				blc[i] = map[x][y];
				i++;

			}

			Arrays.sort(blc);
			double blcMedian = blc[(int) (dim * 0.5)];

			for (int x = 0; x < map.length; x++) {
				map[x][y] = map[x][y] - blcMedian;
			}

		}

		return map;
	}

	public static double[] extractAccumulatedChromatogram(double[][] map, int startX, boolean baselinecorrection) {
		int xdim = map.length;
		int ydim = map[0].length;

		double[] chro = new double[ydim - 2];

		for (int y = 2; y < ydim - 2; y++) {
			for (int x = startX; x < xdim; x++) {
				chro[y] += map[x][y];
			}

		}

		// baselinecorrection of chromatogram
		if (baselinecorrection == true) {
			double[] chro2 = chro.clone();
			Arrays.sort(chro2);
			double chromedian = chro2[(int) (chro.length * 0.01)];
			System.out.println("chromedian = " + chromedian);

			for (int i = 0; i < chro.length; i++) {
				chro[i] -= chromedian;
			}

		}
		return chro;
	}

	public static double[][] normalizeIonizationEnergy(double map[][]) {

		double normEnergy = 1280.0;
		double accumulatedIonEnergy = 0;
		// ~1280 should be
		// soll/ist
		for (int y = 0; y < map[0].length; y++) {
			accumulatedIonEnergy = 0;
			// extracting single spectrum
			for (int x = 0; x < map.length; x++) {
				accumulatedIonEnergy += map[x][y];
			}

			double correction = normEnergy / accumulatedIonEnergy;

			for (int x = 0; x < map.length; x++) {
				map[x][y] = map[x][y] * correction;
			}

			System.out.println(accumulatedIonEnergy);
		}

		return map;
	}

	public static double[][] substract(double[][] mapA, double[][] mapB) {
		double[][] map = new double[mapA.length][mapA[0].length];
		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[0].length; y++) {
				map[x][y] = mapA[x][y] - mapB[x][y];
			}

		}

		return map;
	}

	public static double[][] substractIfValue(double[][] mapA, double[][] mapB) {
		double[][] map = new double[mapA.length][mapA[0].length];
		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[0].length; y++) {
				if (mapA[x][y] > mapB[x][y] * 0.4) {
					map[x][y] = mapA[x][y] - (mapB[x][y]);
				} // *0.5 ? weil um +amp angehoben ?
				else {
					map[x][y] = mapA[x][y];
				}

			}
		}

		return map;
	}

	public static double[][] cutoff(double[][] map, double cutoff) {
		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[0].length; y++) {
				if (map[x][y] <= cutoff) {
					map[x][y] = 0;
				}

			}
		}
		return map;
	}

	public static double[] getScan(int nr, double[][] map) {
		double[] scan = new double[map.length];
		for (int i = 0; i < scan.length; i++) {
			scan[i] = map[i][nr];
		}

		return scan;
	}

	public static void setScan(int nr, double[] scan, double[][] map) {
		for (int i = 0; i < scan.length; i++) {
			map[i][nr] = scan[i];
		}

	}

	// private static double[] interpolate(double[] a, double[] b) {
	// double[] c = new double[a.length];
	// for (int i = 0; i < b.length; i++) {
	// c[i] = (a[i] + b[i]) / 2;
	// }
	//
	// return c;
	// }

	// WARNING THIS DAMAGES THE RTSCALE
	// public static Vector interpolateMissingSpectra(
	// double[][] map, double[] scaleRT) {
	//
	// System.out.print("Interpolating missing spectra ..");
	//
	// // Vector<Double> rtVector = new Vector<Double>();
	// // for (int i = 0; i < scaleRT.length - 1; i++) {
	// // rtVector.add(scaleRT[i] - scaleRT[i + 1]);
	// // }
	// //
	// // Collections.sort(rtVector);
	// // double medianDistance = rtVector.get((int) (rtVector.size() / 2));
	//
	//
	//
	// int singleLinesMissing = 0;
	// Vector<Integer> misses = new Vector<Integer>();
	// for (int i = 0; i
	// < scaleRT.length - 1; i++) {
	// if (Math.abs(scaleRT[i + 1] - scaleRT[i]) == 2) {
	// misses.add(i + 1);
	// singleLinesMissing++;
	//
	// // System.out.println(i + 1 + " is missing");
	// }
	//
	//
	//
	// }
	// System.out.print(".. found " + singleLinesMissing + " ..");
	//
	// double[][] correctedMap = new double[map.length][map[0].length + singleLinesMissing];
	// // double[] correctedScaleRT = new double[scaleRT.length + singleLinesMissing];
	//
	// int oldi = 0;
	// for (int i = 0; i
	// < correctedMap[0].length; i++) {
	// if (misses.contains(i)) {
	//
	// //System.out.println("corrected " + i);
	// // correctedScaleRT[i] = i;
	// double[] speca = getScan(i - 1, map);
	// double[] specb = getScan(i + 1, map);
	// double[] specc = interpolate(speca, specb);
	//
	// for (int a = 0; a
	// < specc.length; a++) {
	// correctedMap[a][i] = specc[a];
	// }
	//
	// } else {
	// // correctedScaleRT[i] = scaleRT[oldi];
	// double[] scan = getScan(oldi, map);
	// setScan(i, scan, correctedMap);
	// oldi++;
	//
	// }
	//
	//
	//
	//
	//
	//
	// }
	//
	// oldi = 0;
	// double[] correctedScaleRT = new double[scaleRT.length + singleLinesMissing];
	// for (int i = 0; i
	// < correctedScaleRT.length; i++) {
	// correctedScaleRT[i] = i;
	// }
	//
	// System.out.println(".. corrected");
	//
	// Vector wrap = new Vector();
	// wrap.add(correctedMap);
	// wrap.add(correctedScaleRT);
	// return wrap;
	//
	//
	// }

	public static int[] histogramm(double[][] map) {
		int rippos = getRipPos(map);
		int xStopp = (int) (rippos * 0.8);
		int xStart = (int) (rippos * 0.2);

		int[] values = new int[100];

		for (int x = xStart; x < xStopp; x++) {
			for (int y = 0; y < map[0].length; y++) {
				int value = (int) (map[x][y] * 100);
				values[value]++;
			}

		}
		return values;
	}

	public static int getSinusFreq(double[][] map) {

		int rippos = getRipPos(map);
		int xStopp = (int) (rippos * 0.8);
		int xStart = 3;// (int)(rippos * 0.2);

		int[] mins = new int[map[0].length];
		int[] maxs = new int[map[0].length];
		int[] freq = new int[map[0].length];

		for (int y = 0; y < map[0].length; y++) {

			double min = 9999999;
			int minpos = -1;
			double max = -9999999;
			int maxpos = -1;

			for (int x = xStart; x < xStopp; x++) {
				if (map[x][y] > max) {
					max = map[x][y];
					maxpos = x;
				}

				if (map[x][y] < min) {
					min = map[x][y];
					minpos = x;
				}

			}
			mins[y] = minpos;
			maxs[y] = maxpos;
			freq[y] = Math.abs(minpos - maxpos);
			// System.out.println(min+" / "+max);
		}

		Arrays.sort(freq);
		return freq[freq.length / 2] * 2;
	}

	public static double getSinusAmp(double[][] map) {

		int rippos = getRipPos(map);
		int xStopp = (int) (rippos * 0.8);
		int xStart = 3;// (int)(rippos * 0.2);

		double[] mins = new double[map[0].length];
		double[] maxs = new double[map[0].length];

		for (int y = 0; y < map[0].length; y++) {

			double min = 9999999;
			double max = -9999999;

			for (int x = xStart; x < xStopp; x++) {
				if (map[x][y] > max) {
					max = map[x][y];
				}

				if (map[x][y] < min) {
					min = map[x][y];
				}

			}
			mins[y] = Math.abs(min);
			maxs[y] = max;
		}

		Arrays.sort(mins);
		Arrays.sort(maxs);

		return (maxs[maxs.length / 2] + mins[mins.length / 2]) / 2;
	}

	public static int[] getSinusShifts(double[][] map) {

		int rippos = getRipPos(map);
		int xStopp = (int) (rippos * 0.8);
		int xStart = 3;// (int)(rippos * 0.2);

		int[] minPositions = new int[map[0].length];
		int[] maxPositions = new int[map[0].length];

		for (int y = 0; y < map[0].length; y++) {

			double min = 9999999;
			int minpos = -1;
			double max = -9999999;
			int maxpos = -1;

			for (int x = xStart; x < xStopp; x++) {
				if (map[x][y] > max) {
					max = map[x][y];
					maxpos = x;
				}

				if (map[x][y] < min) {
					min = map[x][y];
					minpos = x;
				}

			}
			minPositions[y] = minpos + xStart;
			maxPositions[y] = maxpos + xStart;
		}

		int maxmedians[] = new int[maxPositions.length];

		maxmedians[0] = maxPositions[0];
		maxmedians[1] = maxPositions[1];
		maxmedians[2] = maxPositions[2];

		maxmedians[maxPositions.length - 3] = maxPositions[maxPositions.length - 3];
		maxmedians[maxPositions.length - 2] = maxPositions[maxPositions.length - 2];
		maxmedians[maxPositions.length - 1] = maxPositions[maxPositions.length - 1];

		for (int i = 3; i < maxPositions.length - 3; i++) {
			int size = 7;

			int[] med = new int[size];

			med[0] = maxPositions[i - 2];
			med[1] = maxPositions[i - 1];
			med[2] = maxPositions[i];
			med[3] = maxPositions[i + 1];
			med[4] = maxPositions[i + 2];
			med[5] = maxPositions[i + 3];
			med[6] = maxPositions[i - 3];

			Arrays.sort(med);
			maxmedians[i] = med[3];

		}

		int maxmediansplatt[] = new int[maxPositions.length];

		maxmediansplatt[0] = maxmedians[0];
		maxmediansplatt[1] = maxmedians[1];
		maxmediansplatt[2] = maxmedians[2];

		maxmediansplatt[maxPositions.length - 3] = maxmedians[maxPositions.length - 3];
		maxmediansplatt[maxPositions.length - 2] = maxmedians[maxPositions.length - 2];
		maxmediansplatt[maxPositions.length - 1] = maxmedians[maxPositions.length - 1];

		for (int i = 3; i < maxmedians.length - 3; i++) {

			maxmediansplatt[i] = (maxmedians[i - 3] + maxmedians[i - 2] + maxmedians[i - 1] + maxmedians[i]
					+ maxmedians[i + 1] + maxmedians[i + 2] + maxmedians[i + 3]) / 7;
		}

		return maxPositions;

	}

	public static double[][] generateSinusMap(int xSize, int ySize, double amp, double freq, int[] shifts) {

		double[][] sinusMap = new double[xSize][ySize];
		double pi = Math.PI;
		double shift = 0;

		for (int y = 0; y < sinusMap[0].length; y++) {

			shift = ((2 * pi * (double) shifts[y]) / freq);

			for (int x = 0; x < sinusMap.length; x++) {

				sinusMap[x][y] = (amp * Math.sin((2 * pi / freq) * x - shift + 0.5 * pi)) + amp;
				// +amp um den tiefsten punkt der welle bei 0 zu haben und den h�chsten bei 2*amp
			}

		}
		return sinusMap;
	}

	public static double[][] histogramEqualization(double[][] map) {
		System.out.println("Performing histogramm equilization ..");

		int nrOfElemets = 150;

		double[] histogramm = new double[nrOfElemets + 1];
		for (int i = 0; i < histogramm.length; i++) {
			histogramm[i] = 0.0;

		}

		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[0].length; j++) {
				double d = map[i][j];
				histogramm[(int) (d * nrOfElemets)]++;
			}

		}

		for (int i = 0; i < histogramm.length; i++) {
			System.out.println("h" + i + " " + histogramm[i]);
		}

		double[] cHistogramm = histogramm.clone();

		for (int i = 0; i < histogramm.length - 1; i++) {
			cHistogramm[i + 1] += cHistogramm[i];
		}

		double max = Double.NEGATIVE_INFINITY;
		double min = Double.POSITIVE_INFINITY;
		for (int i = 0; i < cHistogramm.length; i++) {
			if (cHistogramm[i] > max) {
				max = cHistogramm[i];
			}

			if (cHistogramm[i] < min) {
				min = cHistogramm[i];
			}

		}

		for (int i = 0; i < histogramm.length; i++) {
			System.out.println("c" + i + " " + cHistogramm[i]);
		}

		for (int i = 0; i < cHistogramm.length; i++) {
			cHistogramm[i] = (cHistogramm[i] - min) / (max - min);
		}

		for (int i = 0; i < histogramm.length; i++) {
			System.out.println("n" + i + " " + cHistogramm[i]);
		}

		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[0].length; j++) {
				map[i][j] = (map[i][j] + cHistogramm[(int) (map[i][j] * (double) nrOfElemets)]) / 2;
			}

		}
		System.out.println(".. done.");
		return map;

	}

	public static double[][] multiplyWith(double[][] map, double factor) {
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[0].length; j++) {
				map[i][j] = map[i][j] * factor;
			}

		}
		return map;
	}

	// public static Peaklist detectPeaksWithWST(double[][] map, double[] scaleK0, double[] scaleRT) {
	//
	//
	//
	//
	//
	// IMSFile imsf = new IMSFile(scaleK0, scaleRT, map);
	// imsf.setFilteredMap(map);
	// WSTpeakfinder wst = new WSTpeakfinder();
	// imsf.detectPeaks(wst);
	// model.detection.Peak[] wstpeaks = imsf.getPeaks();
	//
	//
	// Peaklist wstpl = new Peaklist();
	//
	//
	// for (int i = 0; i < wstpeaks.length; i++) {
	// String[] sa = new String[5];
	// sa[0] = wstpeaks[i].getHeight() + "";
	// sa[1] = scaleK0[wstpeaks[i].getXcenter()] + "";
	// sa[2] = scaleRT[wstpeaks[i].getYcenter()] + "";
	// sa[3] = 4 + "";
	// sa[4] = 0.01 + "";
	//
	// DATA.iDataSetParts.Peak p = new DATA.iDataSetParts.Peak(sa);
	// wstpl.addPeak(p);
	// }
	// return wstpl;
	//
	//
	// }
	public static Peaklist detectPeaksWithWST(boolean coarse, String filename, String timestamp, double[][] map,
			double[] scaleK0, double[] scaleRT) {

		int ripPosIndex = getRipPos(map);//20.12.2011(Enable Rip position correction)
		try {
			map = defaultFilterPipeline(map, true, true, true, true);

			// auto cache when generating peaklists;
			if (HEATMAP_BUFFER_IO.fileInCache(filename) == false) {
				System.out.println("Caching file while generating Peaklist..");
				double[][] jfcmap = HEATMAP_BUFFER_IO.matrixTojfc(map, scaleK0, scaleRT);
				String chachedFileName = filename.replace("iphex.pl", "ims.cca");
				if (!new File("ChartCache/" + chachedFileName).exists()) {
					Vector wrap = new Vector();
					wrap.add(jfcmap);
					wrap.add(jfcmap);
					wrap.add(scaleK0);
					wrap.add(scaleRT);
					HEATMAP_BUFFER_IO.saveToCache(wrap, chachedFileName);
				}
				System.out.println(".. done.");
			}

			double[][] rawMap = new double[map.length][map[0].length];

			for (int i = 0; i < map.length; i++) {
				for (int j = 0; j < map[0].length; j++) {
					rawMap[i][j] = map[i][j];
				}

			}

			ArrayList<MatrixFilter> blFilters = new ArrayList<MatrixFilter>();
			// blFilters.add(new IonizationEnergyNormalizion());
			// blFilters.add(new SimilaritySubstraction());
			// blFilters.add(new Normalization());
			// blFilters.add(new BaseLineCorrection());
			//
			ArrayList<MatrixFilter> smoothFilters = new ArrayList<MatrixFilter>();
			if (coarse) {
				smoothFilters.add(new MeanFilter());
			}
			smoothFilters.add(new GaussFilter());
			smoothFilters.add(new GaussFilter());
			smoothFilters.add(new GaussFilter());

			WSTpeakfinder finder = new WSTpeakfinder();
			// finder param
			finder.setMAX_DISTANCE_TO_FUSE(6.0);
			finder.setSignalToNoise(1.5);// 3.0
			finder.setNoOfBadSpectra(0);
			finder.setCOMPARE_WITH_VOL(true);
			finder.setFUSE_CLOSE_PEAKS(true);

			// generate PeakWaSH process format
			IMSFile file = new IMSFile(scaleK0, scaleRT, map);

			System.out.println("PEAKAXIS: " + scaleRT[0] + " " + scaleRT[scaleRT.length - 1]);

			// process
			file.setFilters(blFilters, smoothFilters);
			file.setFinder(finder);
			file.filterMap();
			file.detectPeaks();

			// export peaklist

			// outputtransform
			String[] header = new String[] { "peak_height", "peak_position_(1/K0)", "peak_position_(RT)",
					"peak_extent_(1/K0)", "peak_extent_(RT)", "ellipse_area" };
			Peaklist pl = new Peaklist(header, timestamp, filename);
			
			//BEGIN 20.12.2011(Enable Rip position correction)
			double ripPositionK0 = scaleK0[ripPosIndex];
			DecimalFormat f4 = new DecimalFormat("0.0000");
			pl.setOriginalRipPosition(f4.format(ripPositionK0));
			//END

			// calculate size under each pixel
			double avgRTstep = (file.getScaleRT()[file.getScaleRT().length - 1] - file.getScaleRT()[0])
					/ file.getScaleRT().length;
			double avgK0step = (file.getScaleK0Inv()[file.getScaleK0Inv().length - 1] - file.getScaleK0Inv()[0])
					/ file.getScaleK0Inv().length;
			double avgArea = avgRTstep * avgK0step;

			DecimalFormat f3 = new DecimalFormat("#.000");
			double zPrecision = 10000.0;

			double cutoff = 0.002;
			for (model.detection.Peak peak : file.getPeaks()) {
				String[] line = new String[6];
				// line[0] = Math.round(peak.getHeight() * precision) / precision + " ";
				line[0] = Math.round(rawMap[peak.getXtop()][peak.getYtop()] * zPrecision) / zPrecision + "";
				line[1] = file.getScaleK0Inv()[peak.getXtop()] + " ";
				line[2] = file.getScaleRT()[peak.getYtop()] + " ";

				line[3] = (avgK0step * peak.getXextend() / 2.0) + " ";
				line[4] = (avgRTstep * peak.getYextend() / 2.0) + " ";
				line[5] = f3.format(avgArea * peak.getVolume());
				if (peak.getHeight() > cutoff) {
					pl.addPeak(new Peak(line));
				}
			}

			return pl;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}

	}

	// load Peaklists to layer panel
	private static double[][] limitPrecision(double[][] map, double precision) {
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[0].length; j++) {
				map[i][j] = Math.round(map[i][j] * precision) / precision;
			}

		}
		return map;
	}

	public static double[][] openWithCutoff(double[][] map, double cutoff) {
		System.out.print("Opening with cutoff " + cutoff + " (5x5) ..");

		double[][] newArray = new double[map.length][map[0].length];

		int maskSize = 3, maskR = (maskSize - 1) / 2, totalElements = maskSize;

		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[0].length; y++) {
				int elementsOverCutoff = 0;

				for (int mx = maskR * -1; mx <= maskR; mx++) {
					for (int my = maskR * -1; my <= maskR; my++) {

						try {
							if (map[x + mx][y + my] > cutoff) {
								elementsOverCutoff++;
							}

						} catch (IndexOutOfBoundsException e) {
							// elementsOverCutoff++;
						}
					}
				}

				if ((elementsOverCutoff / totalElements) < 0.5) { // OPEN
					newArray[x][y] = 0;
				} else {
					newArray[x][y] = map[x][y];
				}
			}
		}
		System.out.println(".. done");
		return newArray;
	}

	public static ArrayList<Double> getPreRipValues(double[][] map, double[] scaleK0, double[] scaleRT) {
		double startK0 = 0.01;
		double stoppK0 = 0.4;
		int RTBorderSkip = 10;

		int bestStartK0Index = -1;
		double bestStartK0Distance = Double.MAX_VALUE;
		int bestStoppK0Index = -1;
		double bestStoppK0Distance = Double.MAX_VALUE;

		for (int i = 0; i < scaleK0.length; i++) {
			double d = scaleK0[i];
			double distanceToStart = Math.abs(startK0 - d);
			if (distanceToStart < bestStartK0Distance) {
				bestStartK0Distance = distanceToStart;
				bestStartK0Index = i;
			}
			double distanceToStopp = Math.abs(stoppK0 - d);
			if (distanceToStopp < bestStoppK0Distance) {
				bestStoppK0Distance = distanceToStopp;
				bestStoppK0Index = i;
			}
		}

		int startK0Index = bestStartK0Index;
		int stoppK0Index = bestStoppK0Index;

		System.out.println(startK0 + " 1/k0 found at index " + startK0Index + " (distance to perfect value: "
				+ bestStartK0Distance + ")");
		System.out.println(stoppK0 + " 1/k0 found at index " + stoppK0Index + " (distance to perfect value: "
				+ bestStoppK0Distance + ")");

		ArrayList<Double> result = new ArrayList<Double>();
		System.out.println("map.length: " + map.length);
		System.out.println("map[0].length: " + map[0].length);
		for (int x = startK0Index; x <= stoppK0Index; x++) {
			for (int y = 0 + RTBorderSkip; y < map[0].length - RTBorderSkip; y++) {
				result.add(map[x][y]);
			}
		}
		return result;
	}

	private static double[][] savitzkyGolayFilter(double[][] map) {
		System.out.print("Savitzky-Golay Filter ..");
		double[][] filtredMap = new double[map.length][map[0].length];
		for (int x = 0; x < map.length; x++) {
			for (int y = 0; y < map[x].length; y++) {
				try {
					filtredMap[x][y] = (map[x + -3][y] * -3 + map[x + -2][y] * 12 + map[x + -1][y] * 17
							+ map[x + +0][y] * 35 + map[x + +1][y] * 17 + map[x + +2][y] * 12 + map[x + +3][y] * -3) / 87;
				} catch (IndexOutOfBoundsException e) {
					filtredMap[x][y] = map[x][y];
				}
			}
		}
		System.out.println(".. done");
		return filtredMap;
	}

	public static double[][] defaultFilterPipeline(double[][] map, boolean ripCompensation, boolean medianFilter,
			boolean sgFilter, boolean gaussFilter) {

		try {
			map = ImageMethods.baselineCorrectionSpectraWise(map);
		} catch (Exception x) {
			System.out.println("Spectrawise baselinecorrection failed, try to correct global");
			try {
				map = ImageMethods.baselineCorrection(map);
			} catch (Exception x2) {
				System.out.println("!!! ERROR !!! global baselinecorrection failed !!!");
			}

		}
		map = normArray(map);

		if (ripCompensation)
			map = ImageMethods.substractSimilaritie(map);

		if (medianFilter)
			map = filterMedian(map, 5);
		if (sgFilter)
			map = savitzkyGolayFilter(map);
		if (gaussFilter)
			map = filterGauss(map);

		map = limitPrecision(map, 10000);
		lastMap = map;
		return map;

	}
}
